package com.sinvo.oa.filter;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sinvo.oa.custom.CustomUser;
import com.sinvo.oa.entity.model.system.SysLoginLog;
import com.sinvo.oa.entity.vo.system.LoginVo;
import com.sinvo.oa.result.R;
import com.sinvo.oa.result.ResultCode;
import com.sinvo.oa.service.SysLoginLogService;
import com.sinvo.oa.util.IpUtils;
import com.sinvo.oa.util.JwtUtils;
import com.sinvo.oa.util.ResponseUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 登录拦截器
 */
public class LoginFilter extends UsernamePasswordAuthenticationFilter {

    private RedisTemplate redisTemplate;

    private SysLoginLogService sysLoginLogService;

    public LoginFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate, SysLoginLogService sysLoginLogService) {
        this.setAuthenticationManager(authenticationManager);
        this.setPostOnly(false);
        //指定登录接口及提交方式
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST"));
        //授权功能 注入redis
        this.redisTemplate = redisTemplate;
        //注入登录日志记录
        this.sysLoginLogService = sysLoginLogService;
    }

    /**
     * 登录认证方法
     *
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            //获取输入用户信息
            LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
            //获取验证码判断
            String verCode = (String) redisTemplate.opsForValue().get("code");
            if (!verCode.equals(loginVo.getVerCode())){
                ResponseUtil.out(response,R.fail(ResultCode.VERCODE_ERROR));
            }
            //封装对象
            Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
            //调用验证方法
            return this.getAuthenticationManager().authenticate(authenticationToken);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 登录成功
     *
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        //获得当前用户
        CustomUser customUser = (CustomUser) authResult.getPrincipal();
        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setUsername(customUser.getUsername());
        loginLog.setIpaddr(IpUtils.getIpAddr(request));
        loginLog.setStatus(1);
        sysLoginLogService.recordLoginLog(loginLog);
        //生成token
        String token = JwtUtils.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());
        //获取用户的权限数据 放在redis
        redisTemplate.opsForValue().set("oa_" + customUser.getUsername(),
                JSON.toJSONString(customUser.getAuthorities()));
        //登录删除redis中的验证码
        redisTemplate.delete("code");
        //封装
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        ResponseUtil.out(response, R.success(map));
    }

    /**
     * 登录失败
     *
     * @param request
     * @param response
     * @param failed
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
        //失败直接抛出异常
        ResponseUtil.out(response, R.fail(ResultCode.LOGIN_ERROR));
    }
}
